<?php

abstract class BaseModel extends CModel
{

    public $errmsg = '服务器异常，请稍后再试';
    public static $db;

    //是否区分用户缓存
    public $diffUser = true;
    //是否使用命名空间
    public $useSpace = true;

    //设置成0则不使用缓存,默认五分钟
    public $cacheTime = 300;
    /**
     * 当前的用户id
     */
    private $uid = 0;

    abstract public function table();

    public function getTableAlias()
    {
        return 't';
    }

    public function getDbConnection()
    {
        if(self::$db!==null)
            return self::$db;
        else
        {
            self::$db=Yii::app()->getDb();
            if(self::$db instanceof CDbConnection)
                return self::$db;
            else
                throw new CDbException(Yii::t('yii','BaseModel requires a "db" CDbConnection application component.'));
        }
    }

    public function getCommandBuilder()
    {
        return $this->getDbConnection()->getSchema()->getCommandBuilder();
    }

    /**
     * 根据 criteria 查询
     *
     */
    public function query($criteria, $all = false)
    {
        if(!$all)
        {
            $criteria->limit=1;
        }
        $command=$this->getCommandBuilder()->createFindCommand($this->table(),$criteria,$this->getTableAlias());
        //缓存的key
        if($this->cacheTime > 0)
        {
            $keyPre = $this->getDbConnection()->connectionString . $this->getDbConnection()->username;
            $cacheKey = md5($keyPre).'|' . $command->getText()  .'-params-'. implode(":", $criteria->params);
            $cr = $this->getFromCache($cacheKey);
            if(false !== $cr)
            {
                return $cr;
            }
        }
        $result = $all ? $command->queryAll() : $command->queryRow();
        if($this->cacheTime > 0)
        {
            $this->setCache($cacheKey, $result,$this->cacheTime);
        }

        return $result;
    }

    /**
     * 查询单条数据
     *
     */
    public function find($condition='',$params=array())
    {
        $criteria=$this->getCommandBuilder()->createCriteria($condition,$params);
        return $this->query($criteria);
    }

    /**
     * 查询一组数据
     *
     */
    public function findAll($condition='',$params=array())
    {
        $criteria=$this->getCommandBuilder()->createCriteria($condition,$params);
        return $this->query($criteria,true);
    }

    /**
     * 查询数据数量
     *
     */
    public function count($condition='',$params=array())
    {
        $builder=$this->getCommandBuilder();
        $criteria=$builder->createCriteria($condition,$params);
        $command = $builder->createCountCommand($this->table(),$criteria);
        //缓存的key
        if($this->cacheTime > 0)
        {
            $keyPre = $this->getDbConnection()->connectionString . $this->getDbConnection()->username;
            $cacheKey = md5($keyPre).'|' . $command->getText()  .'-params-'. implode(":", $criteria->params);
            $cr = $this->getFromCache($cacheKey);
            if(false !== $cr)
            {
                return $cr;
            }
        }
        $result = $command->queryScalar();
        if($this->cacheTime > 0)
        {
            $this->setCache($cacheKey, $result,$this->cacheTime);
        }
        return $result;
    }

    /**
     * 更新数据
     *
     */
    public function updateAll($attributes,$condition='',$params=array())
    {
        $builder=$this->getCommandBuilder();
        $criteria=$builder->createCriteria($condition,$params);
        $command=$builder->createUpdateCommand($this->table(),$attributes,$criteria);
        $rows = $command->execute();
        if($this->cacheTime > 0)
        {
            $rows > 0 && $this->flushCache();
        }
        return $rows;
    }

    /**
     * 删除数据
     *
     */
    public function deleteAll($condition='',$params=array())
    {
        $builder=$this->getCommandBuilder();
        $criteria=$builder->createCriteria($condition,$params);
        $command=$builder->createDeleteCommand($this->table(),$criteria);
        $rows = $command->execute();
        if($this->cacheTime > 0)
        {
            $rows > 0 && $this->flushCache();
        }
        return $rows;
    }

    /**
     * 插入一条数据
     *
     */
    public function insert($attributes=null)
    {
        $builder=$this->getCommandBuilder();
        $table=$this->table();
        $command=$builder->createInsertCommand($table,$attributes);
        if($rows = $command->execute())
        {
            ($this->cacheTime > 0 && $rows > 0) && $this->flushCache();
            return $builder->getLastInsertID($table);
        }
        return false;
    }

    /**
     * 父类的抽象方法
     */
    public function attributeNames()
    {
        return array();
    }

    /**
     * 清空当前表下的所有缓存，当 useSpace 为 true 时 生效
     */
    public function flushCache()
    {
        $this->resetSpace();
    }

    /**
     * 重置命名空间，仅在
     *
     */
    private function resetSpace()
    {
        if(!$this->useSpace)
        {
            return false;
        }
        $key = $this->getSpaceKey();
        $v = $key .':time-' . time() . ':rand-' . mt_rand(0, 100);
        Yii::trace("create new space " . $v, 'model.cache');
        return $this->getCahce()->set($key,$v, 0);
    }

    public function getUid()
    {
        return $this->uid == 0 ? Yii::app()->user->id : $this->uid;
    }

    public function setUid($uid)
    {
        $this->uid = $uid;
    }

    /**
     * 获取某个命名空间的key
     */
    private function getSpaceKey()
    {
        $id = $this->getUid();
        if(!$this->diffUser)
        {
            $id = 0;
        }
        return 'space:uid-' . $id . ':tale-' . $this->table();
    }

    /**
     * 获取缓存空间的值，该值和设置的缓存key组成真正的缓存key
     *
     */
    private function getSpace()
    {
        $key = $this->getSpaceKey();
        if($this->useSpace)
        {
            $spaceKey = $this->getCahce()->get($key);

            $key = false === $spaceKey ? $key : $spaceKey;
        }
        Yii::trace("get space is" . $key, 'model.cache');

        return $key;
    }

    /**
     * 构建缓存的key
     */
    public function buildCacheKey($key, $params = array())
    {
        $keyPre = $this->getSpace();
        $key = $keyPre . ":" . $key;
        !empty($params) && $key . '_'. implode(':', $params);
        Yii::trace("build key is " . $key, 'model.cache');
        return $key;
    }

    /**
     * 写入数据到缓存
     * @param 缓存的key
     * @param $data 缓存的数据
     * @param $time 缓存时间
     * @param $buildKey 是否构建缓存的key
     */
    public function setCache($key,$data,$time, $buildKey = true)
    {
        $cache = $this->getCahce();
        $buildKey && $key = $this->buildCacheKey($key);
        Yii::trace("set cache key is" . $key . 'with params is' . json_encode(array('key'=> $key, 'time' => $time, 'buildKey' => $buildKey)), 'model.cache');
        $cache->set($key, $data, $time);
    }

    public function clearCache($key, $buildKey = true)
    {
        $buildKey && $key = $this->buildCacheKey($key);
        return $this->getCahce()->delete($key);
    }

    public function getFromCache($key, $keyBuild = true)
    {
        $keyBuild && $key = $this->buildCacheKey($key);
        Yii::trace("get from cache by key" . $key, 'model.cache');
        return $this->getCahce()->get($key);
    }

    /**
     * 默认使用cache组件，子类可覆盖
     */
    public function getCahce()
    {
        return Yii::app()->cache;
    }

}